﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Threading;
using SkiaSharp;
using ImageProcessingLib.Models;
using ImageProcessingLib.Logging;
using ImageProcessingLib.Configuration;

namespace ImageProcessingLib
{
    public class ImageProcessor
    {
        private readonly int _maxKB;
        private readonly bool _useParallel;
        private readonly List<string> _supportedFormats;
        private readonly ILogger _logger;

        public ImageProcessor(ImageProcessingOptions options, ILogger logger = null)
        {
            _maxKB = options.MaxKB;
            _useParallel = options.UseParallelProcessing;
            _supportedFormats = options.SupportedFormats.Select(x => x.ToLower()).ToList();
            _logger = logger ?? new ConsoleLogger();
        }
        #region 公共方法：统一入口

        /// <summary>
        /// 统一入口：异步处理指定目录下的最新图片，并返回结果列表
        /// </summary>
        public async Task<List<ProcessedImage>> ProcessImagesAsync(
            string directoryPath,
            int count = 4,
            int maxKB = -1)
        {
            if (string.IsNullOrWhiteSpace(directoryPath) || !Directory.Exists(directoryPath))
            {
                _logger.LogError($"无效的目录路径: {directoryPath}");
                throw new DirectoryNotFoundException("目录不存在");
            }

            try
            {
                var files = ImageHelper.GetLatestImageFiles(directoryPath, count, _supportedFormats);
                _logger.LogInfo($"找到 {files.Count} 张图片，开始处理...");

                if (_useParallel)
                {
                    return await GetLatestImagesAsBytesParallelAsync(directoryPath, count);
                }
                else
                {
                    var result = new List<ProcessedImage>();
                    foreach (var file in files)
                    {
                        byte[] imageData = ProcessAndCompressToBytes(file.FullName, maxKB);
                        var img = new Models.ProcessedImage
                        {
                            FileName = file.Name,
                            Data = imageData,
                            OriginalPath = file.FullName
                        };
                        result.Add(img);
                        _logger.LogInfo($"同步处理完成：{img}");
                    }
                    return result;
                }
            }
            catch (Exception ex)
            {
                _logger.LogError("批量处理图片时发生异常", ex);
                throw;
            }
        }

        #endregion

        #region 同步方法

        public List<ProcessedImage> GetLatestImagesAsBytes(string directoryPath, int count = 4)
        {
            var files = ImageHelper.GetLatestImageFiles(directoryPath, count, _supportedFormats);
            var result = new List<ProcessedImage>();

            foreach (var file in files)
            {
                try
                {
                    byte[] imageData = ProcessAndCompressToBytes(file.FullName, _maxKB);
                    var img = new ProcessedImage
                    {
                        FileName = file.Name,
                        Data = imageData,
                        OriginalPath = file.FullName
                    };

                    result.Add(img);
                    _logger.LogInfo($"同步处理完成：{img}");
                }
                catch (Exception ex)
                {
                    _logger.LogError($"同步处理失败: {file.Name}", ex);
                }
            }

            return result;
        }

        #endregion

        #region 异步并行处理

        public async Task<List<ProcessedImage>> GetLatestImagesAsBytesParallelAsync(string directoryPath, int count = 4)
        {
            var files = ImageHelper.GetLatestImageFiles(directoryPath, count, _supportedFormats);
            var filePaths = files.Select(f => f.FullName).ToList();

            var tasks = filePaths.Select(async filePath =>
            {
                try
                {
                    byte[] data = await ProcessAndCompressToBytesAsync(filePath, _maxKB);
                    var img = new ProcessedImage
                    {
                        FileName = Path.GetFileName(filePath),
                        Data = data,
                        OriginalPath = filePath
                    };

                    _logger.LogInfo($"异步并行处理完成：{img}");
                    return img;
                }
                catch (Exception ex)
                {
                    _logger.LogError($"异步并行处理失败: {filePath}", ex);
                    return null;
                }
            });

            var results = await Task.WhenAll(tasks);
            return results.Where(i => i != null).ToList();
        }

        #endregion

        #region 图像处理核心逻辑

        private byte[] ProcessAndCompressToBytes(string filePath, int maxKB)
        {
            using (var surface = LoadImage(filePath))
            {
                if (maxKB == -1)
                {
                    return EncodeToJpeg(surface, 80);
                }
                else
                {
                    long fileSize = new FileInfo(filePath).Length;
                    if (fileSize <= maxKB * 1024)
                    {
                        return EncodeToJpeg(surface, 80);
                    }
                    else
                    {
                        return CompressSurfaceToBytes(surface, maxKB);
                    }
                }
            }
        }

        private SKSurface LoadImage(string filePath)
        {
            using (var fs = File.OpenRead(filePath))
            using (var data = SKData.Create(fs))
            using (var bitmap = SKBitmap.Decode(data))
            {
                var info = new SKImageInfo(bitmap.Width, bitmap.Height);
                var surface = SKSurface.Create(new SKImageInfo(info.Width, info.Height));
                if (surface == null)
                    throw new InvalidOperationException("无法创建 Skia 表面。");

                surface.Canvas.DrawBitmap(bitmap, 0, 0);
                return surface;
            }
        }

        private byte[] EncodeToJpeg(SKSurface surface, int quality)
        {
            using (var image = surface.Snapshot())
            using (var data = image.Encode(SKEncodedImageFormat.Jpeg, quality))
            {
                return data.ToArray();
            }
        }

        private byte[] CompressSurfaceToBytes(SKSurface surface, int targetMaxKB)
        {
            int quality = 90;

            while (quality >= 10)
            {
                using (var image = surface.Snapshot())
                using (var data = image.Encode(SKEncodedImageFormat.Jpeg, quality))
                {
                    if (data.Size <= targetMaxKB * 1024)
                    {
                        return data.ToArray();
                    }
                }
                quality -= 10;
            }

            // 最低质量强制压缩
            using (var lowestQualityImage = surface.Snapshot())
            using (var lowestData = lowestQualityImage.Encode(SKEncodedImageFormat.Jpeg, 10))
            {
                return lowestData.ToArray();
            }
        }

        private async Task<byte[]> ProcessAndCompressToBytesAsync(string filePath, int maxKB)
        {
            return await Task.Run(() => ProcessAndCompressToBytes(filePath, maxKB));
        }

        #endregion


    }


}